home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / tcl / tkstep0.3b3 / tkstep0 / tkstep / tkConfig.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-08  |  27.2 KB  |  1,003 lines

  1. /* 
  2.  * tkConfig.c --
  3.  *
  4.  *    This file contains the Tk_ConfigureWidget procedure.
  5.  *
  6.  * Copyright (c) 1990-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkConfig.c 1.52 96/02/15 18:52:39
  13.  */
  14.  
  15. #include "tkPort.h"
  16. #include "tk.h"
  17.  
  18. /*
  19.  * Values for "flags" field of Tk_ConfigSpec structures.  Be sure
  20.  * to coordinate these values with those defined in tk.h
  21.  * (TK_CONFIG_COLOR_ONLY, etc.).  There must not be overlap!
  22.  *
  23.  * INIT -        Non-zero means (char *) things have been
  24.  *            converted to Tk_Uid's.
  25.  */
  26.  
  27. #define INIT        0x20
  28.  
  29. /*
  30.  * Forward declarations for procedures defined later in this file:
  31.  */
  32.  
  33. static int        DoConfig _ANSI_ARGS_((Tcl_Interp *interp,
  34.                 Tk_Window tkwin, Tk_ConfigSpec *specPtr,
  35.                 Tk_Uid value, int valueIsUid, char *widgRec));
  36. static Tk_ConfigSpec *    FindConfigSpec _ANSI_ARGS_((Tcl_Interp *interp,
  37.                 Tk_ConfigSpec *specs, char *argvName,
  38.                 int needFlags, int hateFlags));
  39. static char *        FormatConfigInfo _ANSI_ARGS_((Tcl_Interp *interp,
  40.                 Tk_Window tkwin, Tk_ConfigSpec *specPtr,
  41.                 char *widgRec));
  42. static char *        FormatConfigValue _ANSI_ARGS_((Tcl_Interp *interp,
  43.                 Tk_Window tkwin, Tk_ConfigSpec *specPtr,
  44.                 char *widgRec, char *buffer,
  45.                 Tcl_FreeProc **freeProcPtr));
  46.  
  47. /*
  48.  *--------------------------------------------------------------
  49.  *
  50.  * Tk_ConfigureWidget --
  51.  *
  52.  *    Process command-line options and database options to
  53.  *    fill in fields of a widget record with resources and
  54.  *    other parameters.
  55.  *
  56.  * Results:
  57.  *    A standard Tcl return value.  In case of an error,
  58.  *    interp->result will hold an error message.
  59.  *
  60.  * Side effects:
  61.  *    The fields of widgRec get filled in with information
  62.  *    from argc/argv and the option database.  Old information
  63.  *    in widgRec's fields gets recycled.
  64.  *
  65.  *--------------------------------------------------------------
  66.  */
  67.  
  68. int
  69. Tk_ConfigureWidget(interp, tkwin, specs, argc, argv, widgRec, flags)
  70.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  71.     Tk_Window tkwin;        /* Window containing widget (needed to
  72.                  * set up X resources). */
  73.     Tk_ConfigSpec *specs;    /* Describes legal options. */
  74.     int argc;            /* Number of elements in argv. */
  75.     char **argv;        /* Command-line options. */
  76.     char *widgRec;        /* Record whose fields are to be
  77.                  * modified.  Values must be properly
  78.                  * initialized. */
  79.     int flags;            /* Used to specify additional flags
  80.                  * that must be present in config specs
  81.                  * for them to be considered.  Also,
  82.                  * may have TK_CONFIG_ARGV_ONLY set. */
  83. {
  84.     register Tk_ConfigSpec *specPtr;
  85.     Tk_Uid value;        /* Value of option from database. */
  86.     int needFlags;        /* Specs must contain this set of flags
  87.                  * or else they are not considered. */
  88.     int hateFlags;        /* If a spec contains any bits here, it's
  89.                  * not considered. */
  90.  
  91.     needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
  92.     if (Tk_Depth(tkwin) <= 1) {
  93.     hateFlags = TK_CONFIG_COLOR_ONLY;
  94.     } else {
  95.     hateFlags = TK_CONFIG_MONO_ONLY;
  96.     }
  97.  
  98.     /*
  99.      * Pass one:  scan through all the option specs, replacing strings
  100.      * with Tk_Uids (if this hasn't been done already) and clearing
  101.      * the TK_CONFIG_OPTION_SPECIFIED flags.
  102.      */
  103.  
  104.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  105.     if (!(specPtr->specFlags & INIT) && (specPtr->argvName != NULL)) {
  106.         if (specPtr->dbName != NULL) {
  107.         specPtr->dbName = Tk_GetUid(specPtr->dbName);
  108.         }
  109.         if (specPtr->dbClass != NULL) {
  110.         specPtr->dbClass = Tk_GetUid(specPtr->dbClass);
  111.         }
  112.         if (specPtr->defValue != NULL) {
  113.         specPtr->defValue = Tk_GetUid(specPtr->defValue);
  114.         }
  115.     }
  116.     specPtr->specFlags = (specPtr->specFlags & ~TK_CONFIG_OPTION_SPECIFIED)
  117.         | INIT;
  118.     }
  119.  
  120.     /*
  121.      * Pass two:  scan through all of the arguments, processing those
  122.      * that match entries in the specs.
  123.      */
  124.  
  125.     for ( ; argc > 0; argc -= 2, argv += 2) {
  126.     specPtr = FindConfigSpec(interp, specs, *argv, needFlags, hateFlags);
  127.     if (specPtr == NULL) {
  128.         return TCL_ERROR;
  129.     }
  130.     /*
  131.      * Process the entry.
  132.      */
  133.  
  134.     if (argc < 2) {
  135.         Tcl_AppendResult(interp, "value for \"", *argv,
  136.             "\" missing", (char *) NULL);
  137.         return TCL_ERROR;
  138.     }
  139.         
  140.     if ((flags & TK_CONFIG_CHECK_MY_FLAG) &&
  141.         (specPtr->specFlags & TK_CONFIG_DONT_CHANGE_DEFAULT)) {
  142.         continue;
  143.     }
  144.  
  145.     if (DoConfig(interp, tkwin, specPtr, argv[1], 0, widgRec) != TCL_OK) {
  146.         char msg[100];
  147.  
  148.         sprintf(msg, "\n    (processing \"%.40s\" option)",
  149.             specPtr->argvName);
  150.         Tcl_AddErrorInfo(interp, msg);
  151.         return TCL_ERROR;
  152.     }
  153.     specPtr->specFlags |= TK_CONFIG_OPTION_SPECIFIED;
  154.     }
  155.  
  156.     /*
  157.      * Pass three:  scan through all of the specs again;  if no
  158.      * command-line argument matched a spec, then check for info
  159.      * in the option database.  If there was nothing in the
  160.      * database, then use the default.
  161.      */
  162.  
  163.     if (!(flags & TK_CONFIG_ARGV_ONLY)) {
  164.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  165.         if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED)
  166.             || (specPtr->argvName == NULL)
  167.             || (specPtr->type == TK_CONFIG_SYNONYM)) {
  168.         continue;
  169.         }
  170.         if (((specPtr->specFlags & needFlags) != needFlags)
  171.             || (specPtr->specFlags & hateFlags)) {
  172.         continue;
  173.         }
  174.         value = NULL;
  175.         if ((specPtr->dbName != NULL) && !((flags & TK_CONFIG_CHECK_MY_FLAG)
  176.         && (specPtr->specFlags & TK_CONFIG_DONT_CHANGE_DEFAULT))) {
  177.         value = Tk_GetOption(tkwin, specPtr->dbName, specPtr->dbClass);
  178.         }
  179.         if (value != NULL) {
  180.         if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
  181.             TCL_OK) {
  182.             char msg[200];
  183.     
  184.             sprintf(msg, "\n    (%s \"%.50s\" in widget \"%.50s\")",
  185.                 "database entry for",
  186.                 specPtr->dbName, Tk_PathName(tkwin));
  187.             Tcl_AddErrorInfo(interp, msg);
  188.             return TCL_ERROR;
  189.         }
  190.         } else {
  191.         value = specPtr->defValue;
  192.         if ((value != NULL) && !(specPtr->specFlags
  193.             & TK_CONFIG_DONT_SET_DEFAULT)) {
  194.             if (DoConfig(interp, tkwin, specPtr, value, 1, widgRec) !=
  195.                 TCL_OK) {
  196.             char msg[200];
  197.     
  198.             sprintf(msg,
  199.                 "\n    (%s \"%.50s\" in widget \"%.50s\")",
  200.                 "default value for",
  201.                 specPtr->dbName, Tk_PathName(tkwin));
  202.             Tcl_AddErrorInfo(interp, msg);
  203.             return TCL_ERROR;
  204.             }
  205.         }
  206.         }
  207.     }
  208.     }
  209.  
  210.     return TCL_OK;
  211. }
  212.  
  213. /*
  214.  *--------------------------------------------------------------
  215.  *
  216.  * FindConfigSpec --
  217.  *
  218.  *    Search through a table of configuration specs, looking for
  219.  *    one that matches a given argvName.
  220.  *
  221.  * Results:
  222.  *    The return value is a pointer to the matching entry, or NULL
  223.  *    if nothing matched.  In that case an error message is left
  224.  *    in interp->result.
  225.  *
  226.  * Side effects:
  227.  *    None.
  228.  *
  229.  *--------------------------------------------------------------
  230.  */
  231.  
  232. static Tk_ConfigSpec *
  233. FindConfigSpec(interp, specs, argvName, needFlags, hateFlags)
  234.     Tcl_Interp *interp;        /* Used for reporting errors. */
  235.     Tk_ConfigSpec *specs;    /* Pointer to table of configuration
  236.                  * specifications for a widget. */
  237.     char *argvName;        /* Name (suitable for use in a "config"
  238.                  * command) identifying particular option. */
  239.     int needFlags;        /* Flags that must be present in matching
  240.                  * entry. */
  241.     int hateFlags;        /* Flags that must NOT be present in
  242.                  * matching entry. */
  243. {
  244.     register Tk_ConfigSpec *specPtr;
  245.     register char c;        /* First character of current argument. */
  246.     Tk_ConfigSpec *matchPtr;    /* Matching spec, or NULL. */
  247.     size_t length;
  248.  
  249.     c = argvName[1];
  250.     length = strlen(argvName);
  251.     matchPtr = NULL;
  252.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  253.     if (specPtr->argvName == NULL) {
  254.         continue;
  255.     }
  256.     if ((specPtr->argvName[1] != c)
  257.         || (strncmp(specPtr->argvName, argvName, length) != 0)) {
  258.         continue;
  259.     }
  260.     if (((specPtr->specFlags & needFlags) != needFlags)
  261.         || (specPtr->specFlags & hateFlags)) {
  262.         continue;
  263.     }
  264.     if (specPtr->argvName[length] == 0) {
  265.         matchPtr = specPtr;
  266.         goto gotMatch;
  267.     }
  268.     if (matchPtr != NULL) {
  269.         Tcl_AppendResult(interp, "ambiguous option \"", argvName,
  270.             "\"", (char *) NULL);
  271.         return (Tk_ConfigSpec *) NULL;
  272.     }
  273.     matchPtr = specPtr;
  274.     }
  275.  
  276.     if (matchPtr == NULL) {
  277.     Tcl_AppendResult(interp, "unknown option \"", argvName,
  278.         "\"", (char *) NULL);
  279.     return (Tk_ConfigSpec *) NULL;
  280.     }
  281.  
  282.     /*
  283.      * Found a matching entry.  If it's a synonym, then find the
  284.      * entry that it's a synonym for.
  285.      */
  286.  
  287.     gotMatch:
  288.     specPtr = matchPtr;
  289.     if (specPtr->type == TK_CONFIG_SYNONYM) {
  290.     for (specPtr = specs; ; specPtr++) {
  291.         if (specPtr->type == TK_CONFIG_END) {
  292.         Tcl_AppendResult(interp,
  293.             "couldn't find synonym for option \"",
  294.             argvName, "\"", (char *) NULL);
  295.         return (Tk_ConfigSpec *) NULL;
  296.         }
  297.         if ((specPtr->dbName == matchPtr->dbName) 
  298.             && (specPtr->type != TK_CONFIG_SYNONYM)
  299.             && ((specPtr->specFlags & needFlags) == needFlags)
  300.             && !(specPtr->specFlags & hateFlags)) {
  301.         break;
  302.         }
  303.     }
  304.     }
  305.     return specPtr;
  306. }
  307.  
  308. /*
  309.  *--------------------------------------------------------------
  310.  *
  311.  * DoConfig --
  312.  *
  313.  *    This procedure applies a single configuration option
  314.  *    to a widget record.
  315.  *
  316.  * Results:
  317.  *    A standard Tcl return value.
  318.  *
  319.  * Side effects:
  320.  *    WidgRec is modified as indicated by specPtr and value.
  321.  *    The old value is recycled, if that is appropriate for
  322.  *    the value type.
  323.  *
  324.  *--------------------------------------------------------------
  325.  */
  326.  
  327. static int
  328. DoConfig(interp, tkwin, specPtr, value, valueIsUid, widgRec)
  329.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  330.     Tk_Window tkwin;        /* Window containing widget (needed to
  331.                  * set up X resources). */
  332.     Tk_ConfigSpec *specPtr;    /* Specifier to apply. */
  333.     char *value;        /* Value to use to fill in widgRec. */
  334.     int valueIsUid;        /* Non-zero means value is a Tk_Uid;
  335.                  * zero means it's an ordinary string. */
  336.     char *widgRec;        /* Record whose fields are to be
  337.                  * modified.  Values must be properly
  338.                  * initialized. */
  339. {
  340.     char *ptr;
  341.     Tk_Uid uid;
  342.     int nullValue;
  343.  
  344.     nullValue = 0;
  345.     if ((*value == 0) && (specPtr->specFlags & TK_CONFIG_NULL_OK)) {
  346.     nullValue = 1;
  347.     }
  348.  
  349.     do {
  350.     ptr = widgRec + specPtr->offset;
  351.     switch (specPtr->type) {
  352.         case TK_CONFIG_BOOLEAN:
  353.         if (Tcl_GetBoolean(interp, value, (int *) ptr) != TCL_OK) {
  354.             return TCL_ERROR;
  355.         }
  356.         break;
  357.         case TK_CONFIG_INT:
  358.         if (Tcl_GetInt(interp, value, (int *) ptr) != TCL_OK) {
  359.             return TCL_ERROR;
  360.         }
  361.         break;
  362.         case TK_CONFIG_DOUBLE:
  363.         if (Tcl_GetDouble(interp, value, (double *) ptr) != TCL_OK) {
  364.             return TCL_ERROR;
  365.         }
  366.         break;
  367.         case TK_CONFIG_STRING: {
  368.         char *old, *new;
  369.  
  370.         if (nullValue) {
  371.             new = NULL;
  372.         } else {
  373.             new = (char *) ckalloc((unsigned) (strlen(value) + 1));
  374.             strcpy(new, value);
  375.         }
  376.         old = *((char **) ptr);
  377.         if (old != NULL) {
  378.             ckfree(old);
  379.         }
  380.         *((char **) ptr) = new;
  381.         break;
  382.         }
  383.         case TK_CONFIG_UID:
  384.         if (nullValue) {
  385.             *((Tk_Uid *) ptr) = NULL;
  386.         } else {
  387.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  388.             *((Tk_Uid *) ptr) = uid;
  389.         }
  390.         break;
  391.         case TK_CONFIG_COLOR: {
  392.         XColor *newPtr, *oldPtr;
  393.  
  394.         if (nullValue) {
  395.             newPtr = NULL;
  396.         } else {
  397.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  398.             newPtr = Tk_GetColor(interp, tkwin, uid);
  399.             if (newPtr == NULL) {
  400.             return TCL_ERROR;
  401.             }
  402.         }
  403.         oldPtr = *((XColor **) ptr);
  404.         if (oldPtr != NULL) {
  405.             Tk_FreeColor(oldPtr);
  406.         }
  407.         *((XColor **) ptr) = newPtr;
  408.         break;
  409.         }
  410.         case TK_CONFIG_FONT: {
  411.         XFontStruct *newPtr, *oldPtr;
  412.  
  413.         if (nullValue) {
  414.             newPtr = NULL;
  415.         } else {
  416.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  417.             newPtr = Tk_GetFontStruct(interp, tkwin, uid);
  418.             if (newPtr == NULL) {
  419.             return TCL_ERROR;
  420.             }
  421.         }
  422.         oldPtr = *((XFontStruct **) ptr);
  423.         if (oldPtr != NULL) {
  424.             Tk_FreeFontStruct(oldPtr);
  425.         }
  426.         *((XFontStruct **) ptr) = newPtr;
  427.         break;
  428.         }
  429.         case TK_CONFIG_BITMAP: {
  430.         Pixmap new, old;
  431.  
  432.         if (nullValue) {
  433.             new = None;
  434.             } else {
  435.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  436.             new = Tk_GetBitmap(interp, tkwin, uid);
  437.             if (new == None) {
  438.             return TCL_ERROR;
  439.             }
  440.         }
  441.         old = *((Pixmap *) ptr);
  442.         if (old != None) {
  443.             Tk_FreeBitmap(Tk_Display(tkwin), old);
  444.         }
  445.         *((Pixmap *) ptr) = new;
  446.         break;
  447.         }
  448.         case TK_CONFIG_BORDER: {
  449.         Tk_3DBorder new, old;
  450.  
  451.         if (nullValue) {
  452.             new = NULL;
  453.         } else {
  454.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  455.             new = Tk_Get3DBorder(interp, tkwin, uid);
  456.             if (new == NULL) {
  457.             return TCL_ERROR;
  458.             }
  459.         }
  460.         old = *((Tk_3DBorder *) ptr);
  461.         if (old != NULL) {
  462.             Tk_Free3DBorder(old);
  463.         }
  464.         *((Tk_3DBorder *) ptr) = new;
  465.         break;
  466.         }
  467.         case TK_CONFIG_RELIEF:
  468.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  469.         if (Tk_GetRelief(interp, uid, (int *) ptr) != TCL_OK) {
  470.             return TCL_ERROR;
  471.         }
  472.         break;
  473.         case TK_CONFIG_CURSOR:
  474.         case TK_CONFIG_ACTIVE_CURSOR: {
  475.         Tk_Cursor new, old;
  476.  
  477.         if (nullValue) {
  478.             new = None;
  479.         } else {
  480.             uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  481.             new = Tk_GetCursor(interp, tkwin, uid);
  482.             if (new == None) {
  483.             return TCL_ERROR;
  484.             }
  485.         }
  486.         old = *((Tk_Cursor *) ptr);
  487.         if (old != None) {
  488.             Tk_FreeCursor(Tk_Display(tkwin), old);
  489.         }
  490.         *((Tk_Cursor *) ptr) = new;
  491.         if (specPtr->type == TK_CONFIG_ACTIVE_CURSOR) {
  492.             Tk_DefineCursor(tkwin, new);
  493.         }
  494.         break;
  495.         }
  496.         case TK_CONFIG_JUSTIFY:
  497.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  498.         if (Tk_GetJustify(interp, uid, (Tk_Justify *) ptr) != TCL_OK) {
  499.             return TCL_ERROR;
  500.         }
  501.         break;
  502.         case TK_CONFIG_ANCHOR:
  503.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  504.         if (Tk_GetAnchor(interp, uid, (Tk_Anchor *) ptr) != TCL_OK) {
  505.             return TCL_ERROR;
  506.         }
  507.         break;
  508.         case TK_CONFIG_CAP_STYLE:
  509.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  510.         if (Tk_GetCapStyle(interp, uid, (int *) ptr) != TCL_OK) {
  511.             return TCL_ERROR;
  512.         }
  513.         break;
  514.         case TK_CONFIG_JOIN_STYLE:
  515.         uid = valueIsUid ? (Tk_Uid) value : Tk_GetUid(value);
  516.         if (Tk_GetJoinStyle(interp, uid, (int *) ptr) != TCL_OK) {
  517.             return TCL_ERROR;
  518.         }
  519.         break;
  520.         case TK_CONFIG_PIXELS:
  521.         if (Tk_GetPixels(interp, tkwin, value, (int *) ptr)
  522.             != TCL_OK) {
  523.             return TCL_ERROR;
  524.         }
  525.         break;
  526.         case TK_CONFIG_MM:
  527.         if (Tk_GetScreenMM(interp, tkwin, value, (double *) ptr)
  528.             != TCL_OK) {
  529.             return TCL_ERROR;
  530.         }
  531.         break;
  532.         case TK_CONFIG_WINDOW: {
  533.         Tk_Window tkwin2;
  534.  
  535.         if (nullValue) {
  536.             tkwin2 = NULL;
  537.         } else {
  538.             tkwin2 = Tk_NameToWindow(interp, value, tkwin);
  539.             if (tkwin2 == NULL) {
  540.             return TCL_ERROR;
  541.             }
  542.         }
  543.         *((Tk_Window *) ptr) = tkwin2;
  544.         break;
  545.         }
  546.         case TK_CONFIG_CUSTOM:
  547.         if ((*specPtr->customPtr->parseProc)(
  548.             specPtr->customPtr->clientData, interp, tkwin,
  549.             value, widgRec, specPtr->offset) != TCL_OK) {
  550.             return TCL_ERROR;
  551.         }
  552.         break;
  553.         default: {
  554.         sprintf(interp->result, "bad config table: unknown type %d",
  555.             specPtr->type);
  556.         return TCL_ERROR;
  557.         }
  558.     }
  559.     specPtr++;
  560.     } while ((specPtr->argvName == NULL) && (specPtr->type != TK_CONFIG_END));
  561.     return TCL_OK;
  562. }
  563.  
  564. /*
  565.  *--------------------------------------------------------------
  566.  *
  567.  * Tk_ConfigureInfo --
  568.  *
  569.  *    Return information about the configuration options
  570.  *    for a window, and their current values.
  571.  *
  572.  * Results:
  573.  *    Always returns TCL_OK.  Interp->result will be modified
  574.  *    hold a description of either a single configuration option
  575.  *    available for "widgRec" via "specs", or all the configuration
  576.  *    options available.  In the "all" case, the result will
  577.  *    available for "widgRec" via "specs".  The result will
  578.  *    be a list, each of whose entries describes one option.
  579.  *    Each entry will itself be a list containing the option's
  580.  *    name for use on command lines, database name, database
  581.  *    class, default value, and current value (empty string
  582.  *    if none).  For options that are synonyms, the list will
  583.  *    contain only two values:  name and synonym name.  If the
  584.  *    "name" argument is non-NULL, then the only information
  585.  *    returned is that for the named argument (i.e. the corresponding
  586.  *    entry in the overall list is returned).
  587.  *
  588.  * Side effects:
  589.  *    None.
  590.  *
  591.  *--------------------------------------------------------------
  592.  */
  593.  
  594. int
  595. Tk_ConfigureInfo(interp, tkwin, specs, widgRec, argvName, flags)
  596.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  597.     Tk_Window tkwin;        /* Window corresponding to widgRec. */
  598.     Tk_ConfigSpec *specs;    /* Describes legal options. */
  599.     char *widgRec;        /* Record whose fields contain current
  600.                  * values for options. */
  601.     char *argvName;        /* If non-NULL, indicates a single option
  602.                  * whose info is to be returned.  Otherwise
  603.                  * info is returned for all options. */
  604.     int flags;            /* Used to specify additional flags
  605.                  * that must be present in config specs
  606.                  * for them to be considered. */
  607. {
  608.     register Tk_ConfigSpec *specPtr;
  609.     int needFlags, hateFlags;
  610.     char *list;
  611.     char *leader = "{";
  612.  
  613.     needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
  614.     if (Tk_Depth(tkwin) <= 1) {
  615.     hateFlags = TK_CONFIG_COLOR_ONLY;
  616.     } else {
  617.     hateFlags = TK_CONFIG_MONO_ONLY;
  618.     }
  619.  
  620.     /*
  621.      * If information is only wanted for a single configuration
  622.      * spec, then handle that one spec specially.
  623.      */
  624.  
  625.     Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
  626.     if (argvName != NULL) {
  627.     specPtr = FindConfigSpec(interp, specs, argvName, needFlags,
  628.         hateFlags);
  629.     if (specPtr == NULL) {
  630.         return TCL_ERROR;
  631.     }
  632.     interp->result = FormatConfigInfo(interp, tkwin, specPtr, widgRec);
  633.     interp->freeProc = TCL_DYNAMIC;
  634.     return TCL_OK;
  635.     }
  636.  
  637.     /*
  638.      * Loop through all the specs, creating a big list with all
  639.      * their information.
  640.      */
  641.  
  642.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  643.     if ((argvName != NULL) && (specPtr->argvName != argvName)) {
  644.         continue;
  645.     }
  646.     if (((specPtr->specFlags & needFlags) != needFlags)
  647.         || (specPtr->specFlags & hateFlags)) {
  648.         continue;
  649.     }
  650.     if (specPtr->argvName == NULL) {
  651.         continue;
  652.     }
  653.     list = FormatConfigInfo(interp, tkwin, specPtr, widgRec);
  654.     Tcl_AppendResult(interp, leader, list, "}", (char *) NULL);
  655.     ckfree(list);
  656.     leader = " {";
  657.     }
  658.     return TCL_OK;
  659. }
  660.  
  661. /*
  662.  *--------------------------------------------------------------
  663.  *
  664.  * FormatConfigInfo --
  665.  *
  666.  *    Create a valid Tcl list holding the configuration information
  667.  *    for a single configuration option.
  668.  *
  669.  * Results:
  670.  *    A Tcl list, dynamically allocated.  The caller is expected to
  671.  *    arrange for this list to be freed eventually.
  672.  *
  673.  * Side effects:
  674.  *    Memory is allocated.
  675.  *
  676.  *--------------------------------------------------------------
  677.  */
  678.  
  679. static char *
  680. FormatConfigInfo(interp, tkwin, specPtr, widgRec)
  681.     Tcl_Interp *interp;            /* Interpreter to use for things
  682.                      * like floating-point precision. */
  683.     Tk_Window tkwin;            /* Window corresponding to widget. */
  684.     register Tk_ConfigSpec *specPtr;    /* Pointer to information describing
  685.                      * option. */
  686.     char *widgRec;            /* Pointer to record holding current
  687.                      * values of info for widget. */
  688. {
  689.     char *argv[6], *result;
  690.     char buffer[200];
  691.     Tcl_FreeProc *freeProc = (Tcl_FreeProc *) NULL;
  692.  
  693.     argv[0] = specPtr->argvName;
  694.     argv[1] = specPtr->dbName;
  695.     argv[2] = specPtr->dbClass;
  696.     argv[3] = specPtr->defValue;
  697.     if (specPtr->type == TK_CONFIG_SYNONYM) {
  698.     return Tcl_Merge(2, argv);
  699.     }
  700.     argv[4] = FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer,
  701.         &freeProc);
  702.     if (argv[1] == NULL) {
  703.     argv[1] = "";
  704.     }
  705.     if (argv[2] == NULL) {
  706.     argv[2] = "";
  707.     }
  708.     if (argv[3] == NULL) {
  709.     argv[3] = "";
  710.     }
  711.     if (argv[4] == NULL) {
  712.     argv[4] = "";
  713.     }
  714.     result = Tcl_Merge(5, argv);
  715.     if (freeProc != NULL) {
  716.     if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) {
  717.         ckfree(argv[4]);
  718.     } else {
  719.         (*freeProc)(argv[4]);
  720.     }
  721.     }
  722.     return result;
  723. }
  724.  
  725. /*
  726.  *----------------------------------------------------------------------
  727.  *
  728.  * FormatConfigValue --
  729.  *
  730.  *    This procedure formats the current value of a configuration
  731.  *    option.
  732.  *
  733.  * Results:
  734.  *    The return value is the formatted value of the option given
  735.  *    by specPtr and widgRec.  If the value is static, so that it
  736.  *    need not be freed, *freeProcPtr will be set to NULL;  otherwise
  737.  *    *freeProcPtr will be set to the address of a procedure to
  738.  *    free the result, and the caller must invoke this procedure
  739.  *    when it is finished with the result.
  740.  *
  741.  * Side effects:
  742.  *    None.
  743.  *
  744.  *----------------------------------------------------------------------
  745.  */
  746.  
  747. static char *
  748. FormatConfigValue(interp, tkwin, specPtr, widgRec, buffer, freeProcPtr)
  749.     Tcl_Interp *interp;        /* Interpreter for use in real conversions. */
  750.     Tk_Window tkwin;        /* Window corresponding to widget. */
  751.     Tk_ConfigSpec *specPtr;    /* Pointer to information describing option.
  752.                  * Must not point to a synonym option. */
  753.     char *widgRec;        /* Pointer to record holding current
  754.                  * values of info for widget. */
  755.     char *buffer;        /* Static buffer to use for small values.
  756.                  * Must have at least 200 bytes of storage. */
  757.     Tcl_FreeProc **freeProcPtr;    /* Pointer to word to fill in with address
  758.                  * of procedure to free the result, or NULL
  759.                  * if result is static. */
  760. {
  761.     char *ptr, *result;
  762.  
  763.     *freeProcPtr = NULL;
  764.     ptr = widgRec + specPtr->offset;
  765.     result = "";
  766.     switch (specPtr->type) {
  767.     case TK_CONFIG_BOOLEAN:
  768.         if (*((int *) ptr) == 0) {
  769.         result = "0";
  770.         } else {
  771.         result = "1";
  772.         }
  773.         break;
  774.     case TK_CONFIG_INT:
  775.         sprintf(buffer, "%d", *((int *) ptr));
  776.         result = buffer;
  777.         break;
  778.     case TK_CONFIG_DOUBLE:
  779.         Tcl_PrintDouble(interp, *((double *) ptr), buffer);
  780.         result = buffer;
  781.         break;
  782.     case TK_CONFIG_STRING:
  783.         result = (*(char **) ptr);
  784.         if (result == NULL) {
  785.         result = "";
  786.         }
  787.         break;
  788.     case TK_CONFIG_UID: {
  789.         Tk_Uid uid = *((Tk_Uid *) ptr);
  790.         if (uid != NULL) {
  791.         result = uid;
  792.         }
  793.         break;
  794.     }
  795.     case TK_CONFIG_COLOR: {
  796.         XColor *colorPtr = *((XColor **) ptr);
  797.         if (colorPtr != NULL) {
  798.         result = Tk_NameOfColor(colorPtr);
  799.         }
  800.         break;
  801.     }
  802.     case TK_CONFIG_FONT: {
  803.         XFontStruct *fontStructPtr = *((XFontStruct **) ptr);
  804.         if (fontStructPtr != NULL) {
  805.         result = Tk_NameOfFontStruct(fontStructPtr);
  806.         }
  807.         break;
  808.     }
  809.     case TK_CONFIG_BITMAP: {
  810.         Pixmap pixmap = *((Pixmap *) ptr);
  811.         if (pixmap != None) {
  812.         result = Tk_NameOfBitmap(Tk_Display(tkwin), pixmap);
  813.         }
  814.         break;
  815.     }
  816.     case TK_CONFIG_BORDER: {
  817.         Tk_3DBorder border = *((Tk_3DBorder *) ptr);
  818.         if (border != NULL) {
  819.         result = Tk_NameOf3DBorder(border);
  820.         }
  821.         break;
  822.     }
  823.     case TK_CONFIG_RELIEF:
  824.         result = Tk_NameOfRelief(*((int *) ptr));
  825.         break;
  826.     case TK_CONFIG_CURSOR:
  827.     case TK_CONFIG_ACTIVE_CURSOR: {
  828.         Tk_Cursor cursor = *((Tk_Cursor *) ptr);
  829.         if (cursor != None) {
  830.         result = Tk_NameOfCursor(Tk_Display(tkwin), cursor);
  831.         }
  832.         break;
  833.     }
  834.     case TK_CONFIG_JUSTIFY:
  835.         result = Tk_NameOfJustify(*((Tk_Justify *) ptr));
  836.         break;
  837.     case TK_CONFIG_ANCHOR:
  838.         result = Tk_NameOfAnchor(*((Tk_Anchor *) ptr));
  839.         break;
  840.     case TK_CONFIG_CAP_STYLE:
  841.         result = Tk_NameOfCapStyle(*((int *) ptr));
  842.         break;
  843.     case TK_CONFIG_JOIN_STYLE:
  844.         result = Tk_NameOfJoinStyle(*((int *) ptr));
  845.         break;
  846.     case TK_CONFIG_PIXELS:
  847.         sprintf(buffer, "%d", *((int *) ptr));
  848.         result = buffer;
  849.         break;
  850.     case TK_CONFIG_MM:
  851.         Tcl_PrintDouble(interp, *((double *) ptr), buffer);
  852.         result = buffer;
  853.         break;
  854.     case TK_CONFIG_WINDOW: {
  855.         Tk_Window tkwin;
  856.  
  857.         tkwin = *((Tk_Window *) ptr);
  858.         if (tkwin != NULL) {
  859.         result = Tk_PathName(tkwin);
  860.         }
  861.         break;
  862.     }
  863.     case TK_CONFIG_CUSTOM:
  864.         result = (*specPtr->customPtr->printProc)(
  865.             specPtr->customPtr->clientData, tkwin, widgRec,
  866.             specPtr->offset, freeProcPtr);
  867.         break;
  868.     default: 
  869.         result = "?? unknown type ??";
  870.     }
  871.     return result;
  872. }
  873.  
  874. /*
  875.  *----------------------------------------------------------------------
  876.  *
  877.  * Tk_ConfigureValue --
  878.  *
  879.  *    This procedure returns the current value of a configuration
  880.  *    option for a widget.
  881.  *
  882.  * Results:
  883.  *    The return value is a standard Tcl completion code (TCL_OK or
  884.  *    TCL_ERROR).  Interp->result will be set to hold either the value
  885.  *    of the option given by argvName (if TCL_OK is returned) or
  886.  *    an error message (if TCL_ERROR is returned).
  887.  *
  888.  * Side effects:
  889.  *    None.
  890.  *
  891.  *----------------------------------------------------------------------
  892.  */
  893.  
  894. int
  895. Tk_ConfigureValue(interp, tkwin, specs, widgRec, argvName, flags)
  896.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  897.     Tk_Window tkwin;        /* Window corresponding to widgRec. */
  898.     Tk_ConfigSpec *specs;    /* Describes legal options. */
  899.     char *widgRec;        /* Record whose fields contain current
  900.                  * values for options. */
  901.     char *argvName;        /* Gives the command-line name for the
  902.                  * option whose value is to be returned. */
  903.     int flags;            /* Used to specify additional flags
  904.                  * that must be present in config specs
  905.                  * for them to be considered. */
  906. {
  907.     Tk_ConfigSpec *specPtr;
  908.     int needFlags, hateFlags;
  909.  
  910.     needFlags = flags & ~(TK_CONFIG_USER_BIT - 1);
  911.     if (Tk_Depth(tkwin) <= 1) {
  912.     hateFlags = TK_CONFIG_COLOR_ONLY;
  913.     } else {
  914.     hateFlags = TK_CONFIG_MONO_ONLY;
  915.     }
  916.     specPtr = FindConfigSpec(interp, specs, argvName, needFlags, hateFlags);
  917.     if (specPtr == NULL) {
  918.     return TCL_ERROR;
  919.     }
  920.     interp->result = FormatConfigValue(interp, tkwin, specPtr, widgRec,
  921.         interp->result, &interp->freeProc);
  922.     return TCL_OK;
  923. }
  924.  
  925. /*
  926.  *----------------------------------------------------------------------
  927.  *
  928.  * Tk_FreeOptions --
  929.  *
  930.  *    Free up all resources associated with configuration options.
  931.  *
  932.  * Results:
  933.  *    None.
  934.  *
  935.  * Side effects:
  936.  *    Any resource in widgRec that is controlled by a configuration
  937.  *    option (e.g. a Tk_3DBorder or XColor) is freed in the appropriate
  938.  *    fashion.
  939.  *
  940.  *----------------------------------------------------------------------
  941.  */
  942.  
  943.     /* ARGSUSED */
  944. void
  945. Tk_FreeOptions(specs, widgRec, display, needFlags)
  946.     Tk_ConfigSpec *specs;    /* Describes legal options. */
  947.     char *widgRec;        /* Record whose fields contain current
  948.                  * values for options. */
  949.     Display *display;        /* X display; needed for freeing some
  950.                  * resources. */
  951.     int needFlags;        /* Used to specify additional flags
  952.                  * that must be present in config specs
  953.                  * for them to be considered. */
  954. {
  955.     register Tk_ConfigSpec *specPtr;
  956.     char *ptr;
  957.  
  958.     for (specPtr = specs; specPtr->type != TK_CONFIG_END; specPtr++) {
  959.     if ((specPtr->specFlags & needFlags) != needFlags) {
  960.         continue;
  961.     }
  962.     ptr = widgRec + specPtr->offset;
  963.     switch (specPtr->type) {
  964.         case TK_CONFIG_STRING:
  965.         if (*((char **) ptr) != NULL) {
  966.             ckfree(*((char **) ptr));
  967.             *((char **) ptr) = NULL;
  968.         }
  969.         break;
  970.         case TK_CONFIG_COLOR:
  971.         if (*((XColor **) ptr) != NULL) {
  972.             Tk_FreeColor(*((XColor **) ptr));
  973.             *((XColor **) ptr) = NULL;
  974.         }
  975.         break;
  976.         case TK_CONFIG_FONT:
  977.         if (*((XFontStruct **) ptr) != NULL) {
  978.             Tk_FreeFontStruct(*((XFontStruct **) ptr));
  979.             *((XFontStruct **) ptr) = NULL;
  980.         }
  981.         break;
  982.         case TK_CONFIG_BITMAP:
  983.         if (*((Pixmap *) ptr) != None) {
  984.             Tk_FreeBitmap(display, *((Pixmap *) ptr));
  985.             *((Pixmap *) ptr) = None;
  986.         }
  987.         break;
  988.         case TK_CONFIG_BORDER:
  989.         if (*((Tk_3DBorder *) ptr) != NULL) {
  990.             Tk_Free3DBorder(*((Tk_3DBorder *) ptr));
  991.             *((Tk_3DBorder *) ptr) = NULL;
  992.         }
  993.         break;
  994.         case TK_CONFIG_CURSOR:
  995.         case TK_CONFIG_ACTIVE_CURSOR:
  996.         if (*((Tk_Cursor *) ptr) != None) {
  997.             Tk_FreeCursor(display, *((Tk_Cursor *) ptr));
  998.             *((Tk_Cursor *) ptr) = None;
  999.         }
  1000.     }
  1001.     }
  1002. }
  1003.